/*     */ package com.zimbra.cs.service.util;
/*     */ 
/*     */ import com.google.common.base.Objects;
/*     */ import com.google.common.base.Objects.ToStringHelper;
/*     */ import com.google.common.base.Strings;
/*     */ import com.google.common.collect.Lists;
/*     */ import com.sun.mail.smtp.SMTPMessage;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.mime.shim.JavaMailInternetAddress;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.common.zmime.ZMimeBodyPart;
/*     */ import com.zimbra.common.zmime.ZMimeMultipart;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.Config;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailSender;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.MailboxManager;
/*     */ import com.zimbra.cs.mailbox.Message;
/*     */ import com.zimbra.cs.mailbox.OperationContext;
/*     */ import com.zimbra.cs.mime.MailboxBlobDataSource;
/*     */ import com.zimbra.cs.mime.Mime;
/*     */ import com.zimbra.cs.store.MailboxBlob;
/*     */ import com.zimbra.cs.util.JMSession;
/*     */ import java.util.ArrayList;
/*     */ import java.util.List;
/*     */ import java.util.regex.Matcher;
/*     */ import java.util.regex.Pattern;
/*     */ import javax.activation.DataHandler;
/*     */ import javax.mail.Message.RecipientType;
/*     */ import javax.mail.MessagingException;
/*     */ import javax.mail.Transport;
/*     */ import javax.mail.internet.InternetAddress;
/*     */ import javax.mail.internet.MimeBodyPart;
/*     */ import javax.mail.internet.MimeMessage;
/*     */ import javax.mail.internet.MimeMultipart;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class SpamHandler
/*     */ {
/*  62 */   private static Log log = LogFactory.getLog(SpamHandler.class);
/*     */   private static SpamHandler spamHandler;
/*     */   
/*     */   public static synchronized SpamHandler getInstance()
/*     */   {
/*  67 */     if (spamHandler == null) {
/*  68 */       spamHandler = new SpamHandler();
/*     */     }
/*  70 */     return spamHandler;
/*     */   }
/*     */   
/*     */   public SpamHandler() {
/*  74 */     Runnable r = new Runnable()
/*     */     {
/*     */       public void run() {
/*  77 */         SpamHandler.this.reportLoop();
/*     */       }
/*  79 */     };
/*  80 */     Thread spamHandlerThread = new Thread(r);
/*  81 */     spamHandlerThread.setName("Junk-NotJunk-Handler");
/*  82 */     spamHandlerThread.setDaemon(true);
/*  83 */     spamHandlerThread.start();
/*     */   }
/*     */   
/*     */   private void sendReport(SpamReport sr) throws ServiceException, MessagingException {
/*  87 */     Config config = Provisioning.getInstance().getConfig();
/*  88 */     String isSpamString = sr.isSpam ? config.getSpamReportTypeSpam() : config.getSpamReportTypeHam();
/*  89 */     SMTPMessage out = new SMTPMessage(JMSession.getSmtpSession());
/*     */     
/*  91 */     Mailbox mbox = MailboxManager.getInstance().getMailboxById(sr.mailboxId);
/*  92 */     Message msg = mbox.getMessageById(null, sr.messageId);
/*     */     
/*  94 */     MimeMultipart mmp = new ZMimeMultipart("mixed");
/*     */     
/*  96 */     MimeBodyPart infoPart = new ZMimeBodyPart();
/*  97 */     infoPart.setHeader("Content-Description", "Zimbra spam classification report");
/*  98 */     String body = String.format("Classified-By: %s\r\nClassified-As: %s\r\nAction: %s\r\nSource-Folder: %s\r\nDestination-Folder: %s\r\nDestination-Mailbox: %s\r\n", new Object[] { Strings.nullToEmpty(sr.accountName), isSpamString, Strings.nullToEmpty(sr.action), Strings.nullToEmpty(sr.sourceFolder), Strings.nullToEmpty(sr.destFolder), Strings.nullToEmpty(sr.destAccountName) });
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 108 */     infoPart.setText(body);
/* 109 */     mmp.addBodyPart(infoPart);
/*     */     
/* 111 */     MailboxBlob blob = msg.getBlob();
/* 112 */     MimeBodyPart mbp = new ZMimeBodyPart();
/* 113 */     mbp.setDataHandler(new DataHandler(new MailboxBlobDataSource(blob)));
/* 114 */     mbp.setHeader("Content-Type", "message/rfc822");
/* 115 */     mbp.setHeader("Content-Disposition", "attachment");
/* 116 */     mmp.addBodyPart(mbp);
/*     */     
/* 118 */     out.setContent(mmp);
/*     */     
/* 120 */     out.addHeader(config.getSpamReportSenderHeader(), sr.accountName);
/* 121 */     out.addHeader(config.getSpamReportTypeHeader(), isSpamString);
/*     */     
/* 123 */     if ((config.isSmtpSendAddOriginatingIP()) && (sr.origIp != null)) {
/* 124 */       out.addHeader("X-Originating-IP", MailSender.formatXOrigIpHeader(sr.origIp));
/*     */     }
/* 126 */     out.setRecipient(Message.RecipientType.TO, sr.reportRecipient);
/* 127 */     out.setEnvelopeFrom(config.getSpamReportEnvelopeFrom());
/* 128 */     out.setSubject("zimbra-spam-report: " + sr.accountName + ": " + isSpamString);
/* 129 */     Transport.send(out);
/*     */     
/* 131 */     ZimbraLog.misc.info("Sent " + sr);
/*     */   }
/*     */   
/*     */ 
/*     */   public static final class SpamReport
/*     */   {
/*     */     private final boolean isSpam;
/*     */     
/*     */     private final String action;
/*     */     
/*     */     private final String destFolder;
/*     */     private String sourceFolder;
/*     */     private String destAccountName;
/*     */     private String accountName;
/*     */     private InternetAddress reportRecipient;
/*     */     private String origIp;
/*     */     private int messageId;
/*     */     private int mailboxId;
/*     */     
/*     */     public SpamReport(boolean isSpam, String action, String destFolder)
/*     */     {
/* 152 */       this.isSpam = isSpam;
/* 153 */       this.action = action;
/* 154 */       this.destFolder = destFolder;
/*     */     }
/*     */     
/*     */     SpamReport(SpamReport report) {
/* 158 */       this.isSpam = report.isSpam;
/* 159 */       this.action = report.action;
/* 160 */       this.destFolder = report.destFolder;
/* 161 */       this.sourceFolder = report.sourceFolder;
/* 162 */       this.destAccountName = report.destAccountName;
/* 163 */       this.accountName = report.accountName;
/* 164 */       this.reportRecipient = report.reportRecipient;
/* 165 */       this.origIp = report.origIp;
/* 166 */       this.messageId = report.messageId;
/* 167 */       this.mailboxId = report.mailboxId;
/*     */     }
/*     */     
/*     */     public void setSourceFolderPath(String path) {
/* 171 */       this.sourceFolder = path;
/*     */     }
/*     */     
/*     */     public void setDestAccountName(String name) {
/* 175 */       this.destAccountName = name;
/*     */     }
/*     */     
/*     */     public String toString() {
/* 179 */       return Objects.toStringHelper(this).add("account", this.accountName).add("mbox", this.mailboxId).add("msgId", this.messageId).add("isSpam", this.isSpam).add("origIp", this.origIp).add("action", this.action).add("srcFolder", this.sourceFolder).add("destFolder", this.destFolder).add("destAccount", this.destAccountName).add("reportRecipient", this.reportRecipient).toString();
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 193 */   private static final int spamReportQueueSize = LC.zimbra_spam_report_queue_size.intValue();
/*     */   
/* 195 */   private final Object spamReportQueueLock = new Object();
/*     */   
/* 197 */   List<SpamReport> spamReportQueue = new ArrayList(spamReportQueueSize);
/*     */   private static String spamHeaderValue;
/*     */   private static Pattern spamPattern;
/*     */   
/*     */   void reportLoop() { for (;;) { List<SpamReport> workQueue;
/* 202 */       synchronized (this.spamReportQueueLock) {
/* 203 */         if (this.spamReportQueue.size() == 0) {
/*     */           try {
/* 205 */             this.spamReportQueueLock.wait();
/*     */           } catch (InterruptedException ie) {
/* 207 */             ZimbraLog.misc.warn("SpamHandler interrupted", ie); }
/* 208 */           continue;
/*     */         }
/* 210 */         workQueue = this.spamReportQueue;
/* 211 */         this.spamReportQueue = new ArrayList(spamReportQueueSize);
/*     */       }
/*     */       
/* 214 */       if (workQueue == null) {
/* 215 */         if (ZimbraLog.misc.isDebugEnabled()) ZimbraLog.misc.debug("SpamHandler nothing to drain");
/*     */       } else {
/* 217 */         for (SpamReport sr : workQueue) {
/*     */           try {
/* 219 */             sendReport(sr);
/*     */           }
/*     */           catch (Exception e) {
/* 222 */             ZimbraLog.misc.warn("exception occurred sending spam report " + sr, e);
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   private void enqueue(List<SpamReport> reports) {
/* 230 */     synchronized (this.spamReportQueueLock) {
/* 231 */       for (SpamReport report : reports)
/* 232 */         if (this.spamReportQueue.size() > spamReportQueueSize) {
/* 233 */           ZimbraLog.misc.warn("SpamHandler queue size " + this.spamReportQueue.size() + " too large, ignored " + report);
/*     */         }
/*     */         else {
/* 236 */           this.spamReportQueue.add(report);
/* 237 */           ZimbraLog.misc.debug("SpamHandler enqueued %s", new Object[] { report });
/*     */         }
/* 239 */       this.spamReportQueueLock.notify();
/*     */     }
/*     */   }
/*     */   
/*     */   public void handle(OperationContext octxt, Mailbox mbox, int itemId, MailItem.Type type, SpamReport report) throws ServiceException
/*     */   {
/* 245 */     Config config = Provisioning.getInstance().getConfig();
/*     */     String address;
/* 247 */     if (report.isSpam) {
/* 248 */       String address = config.getSpamIsSpamAccount();
/* 249 */       if (Strings.isNullOrEmpty(address)) {
/* 250 */         log.debug("Spam address is not set.  Nothing to do.");
/*     */       }
/*     */     }
/*     */     else {
/* 254 */       address = config.getSpamIsNotSpamAccount();
/* 255 */       if (Strings.isNullOrEmpty(address)) {
/* 256 */         log.debug("Ham address is not set.  Nothing to do.");
/* 257 */         return;
/*     */       }
/*     */     }
/*     */     try
/*     */     {
/* 262 */       report.reportRecipient = new JavaMailInternetAddress(address, true);
/*     */     } catch (MessagingException e) {
/* 264 */       throw ServiceException.INVALID_REQUEST("Invalid address: " + address, e);
/*     */     }
/*     */     
/* 267 */     report.accountName = mbox.getAccount().getName();
/* 268 */     report.mailboxId = mbox.getId();
/* 269 */     if (octxt != null) {
/* 270 */       report.origIp = octxt.getRequestIP();
/*     */     }
/*     */     
/* 273 */     List<SpamReport> reports = Lists.newArrayList();
/* 274 */     switch (type) {
/*     */     case MESSAGE: 
/* 276 */       report.messageId = itemId;
/* 277 */       reports.add(report);
/* 278 */       break;
/*     */     case CONVERSATION: 
/* 280 */       for (Message msg : mbox.getMessagesByConversation(null, itemId)) {
/* 281 */         SpamReport msgReport = new SpamReport(report);
/* 282 */         msgReport.messageId = msg.getId();
/* 283 */         reports.add(report);
/*     */       }
/* 285 */       break;
/*     */     default: 
/* 287 */       ZimbraLog.misc.warn("SpamHandler called on unhandled item type=" + type + " account=" + report.accountName + " id=" + itemId);
/*     */       
/* 289 */       return;
/*     */     }
/*     */     
/* 292 */     enqueue(reports);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static String whitelistHeaderValue;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static Pattern whitelistPattern;
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static boolean isSpam(MimeMessage msg)
/*     */   {
/*     */     try
/*     */     {
/* 326 */       Config config = Provisioning.getInstance().getConfig();
/*     */       
/* 328 */       String whitelistHeader = config.getSpamWhitelistHeader();
/* 329 */       if (whitelistHeader != null) {
/* 330 */         String whitelistHeaderValue = config.getSpamWhitelistHeaderValue();
/* 331 */         if (whitelistHeaderValue != null) {
/* 332 */           if (!whitelistHeaderValue.equals(whitelistHeaderValue))
/*     */           {
/* 334 */             whitelistHeaderValue = whitelistHeaderValue;
/* 335 */             whitelistPattern = Pattern.compile(whitelistHeaderValue);
/*     */           }
/*     */           
/* 338 */           String[] values = Mime.getHeaders(msg, whitelistHeader);
/* 339 */           boolean matched = false;
/* 340 */           for (String val : values) {
/* 341 */             Matcher m = whitelistPattern.matcher(val);
/* 342 */             if (m.matches()) {
/* 343 */               matched = true;
/*     */             } else {
/* 345 */               matched = false;
/* 346 */               break;
/*     */             }
/*     */           }
/* 349 */           if (matched) {
/* 350 */             return false;
/*     */           }
/*     */         }
/*     */       }
/*     */       
/* 355 */       String spamHeader = config.getSpamHeader();
/* 356 */       if (spamHeader != null) {
/* 357 */         String spamHeaderValue = config.getSpamHeaderValue();
/* 358 */         if (spamHeaderValue != null) {
/* 359 */           if (!spamHeaderValue.equals(spamHeaderValue))
/*     */           {
/* 361 */             spamHeaderValue = spamHeaderValue;
/* 362 */             spamPattern = Pattern.compile(spamHeaderValue);
/*     */           }
/*     */           
/* 365 */           String[] values = Mime.getHeaders(msg, spamHeader);
/* 366 */           for (String val : values) {
/* 367 */             Matcher m = spamPattern.matcher(val);
/* 368 */             if (m.matches()) {
/* 369 */               return true;
/*     */             }
/*     */           }
/*     */         }
/*     */       }
/*     */     } catch (Exception e) {
/* 375 */       ZimbraLog.mailbox.warn("Unable to determine whether the message is spam.", e);
/*     */     }
/* 377 */     return false;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/service/util/SpamHandler.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */